#include "Expression.h"
#include "Exceptions.h"
//#include <string>
#include <ctype.h>

namespace SymCe{

	bool good_variable_name(char * name){	//checks if the variable name is good
		while (*name != '\0'){
			if(!isalpha(*name)){
				return false;
			}
			name++;
		}
		return true;
	}

	/*Expression::Expression(Integer num){
		tree = new Multitree;
		tree->symbol.type = NUMBER;
		tree->symbol.number = num;
		tree->childs = NULL;
	}*/

	Expression::Expression(Number fr){
		tree = new Multitree;
		tree->symbol.type=NUMBER;
		tree->symbol.number=fr;
		tree->childs = NULL;
	}

	Expression::Expression(const Expression & ex){
		tree = copy_tree(ex.tree);
	}

	Expression::Expression(){
		tree = NULL;
	}

	Expression::~Expression(){
		delete_tree(tree);
		tree = NULL;
	}

	Expression::Expression(OperatorType op, bool inv, Multitree * left, Multitree * right){
		tree = new Multitree;
		tree->symbol.type = OPERATOR;
		tree->symbol.oper = op;
		ListOfChilds * childs = new ListOfChilds;
		childs->inverted = false;
		childs->subtree = copy_tree(left);

		childs->next = new ListOfChilds;
		childs->next->subtree = copy_tree(right);
		childs->next->inverted = inv;
		childs->next->next = NULL;
		tree->childs = childs;
		rehang_tree(tree);
		sort_tree(tree);
	}

	Expression::Expression(char * variable){
//		char * variable = new char[var.size()+1];
//		strcpy(variable, var.c_str());
		if(!good_variable_name(variable)){
			delete variable;
			throw BadVariable();
		}
		tree = new Multitree;
		tree->symbol.name = new char[strlen(variable)+1];
		tree->symbol.type = VARIABLE;
		strcpy(tree->symbol.name, variable); //We can use strcpy, because we have enough memory (because of strlen).
//		delete variable;
		tree->childs = NULL;
	}

	Expression::Expression(char * constantname, Number value){
		if(!good_variable_name(constantname)){
			throw BadVariable();
		}
		tree = new Multitree;
		tree->symbol.name = new char[strlen(constantname)+1];
		tree->symbol.type = CONSTANT;
		strcpy(tree->symbol.name, constantname);
		tree->symbol.number = value;
		tree->childs = NULL;
	}


	Expression & Expression::operator=(const Expression & ex){
		if(this != &ex){
			delete_tree(tree);
			tree=copy_tree(ex.tree);
		}
		return * this;
	}


//BINARY OPERATORS - they are almost same. We just change type of symbol and/or inverted for
//second operand
	Expression Expression::operator+(const Expression & ex) const{
		Expression temp = Expression(PLUS, false, this->tree, ex.tree);
		return temp.reduce();
	}

	Expression Expression::operator-(const Expression & ex) const{
		Expression temp = Expression(PLUS, true, this->tree, ex.tree);
		return temp.reduce();
	}

	Expression Expression::operator*(const Expression & ex) const{
		Expression temp = Expression(MULTIPLY, false, this->tree, ex.tree);
		return temp.reduce();
	}

	Expression Expression::operator/(const Expression & ex) const{
		Expression temp = Expression(MULTIPLY, true, this->tree, ex.tree);
		return temp.reduce();
	}

	Expression Expression::operator^(const Expression & ex) const{
		Expression temp = Expression(POWER, false, this->tree, ex.tree);
		return temp.reduce();
	}

	std::ostream & operator<<(std::ostream & stream, Expression & ex){
		return ex.output(stream);
	}

	std::ostream & operator<<(std::ostream & stream, Expression const & ex){
		return ex.output(stream);
	}

	std::ostream & Expression::output(std::ostream & stream){
		return output_tree(tree, stream);
	}

	std::ostream & Expression::output(std::ostream & stream) const{
		return output_tree(tree, stream);
	}


	Expression tan(Expression & ex){
		Expression temp = ex.tan();
		return temp.reduce();
	}

	Expression ln(Expression & ex){
		Expression temp = ex.ln();
		return temp.reduce();
	}

	Expression sin(Expression & ex){
		Expression temp = ex.sin();
		return temp.reduce();
	}

	Expression cos(Expression & ex){
		Expression temp = ex.cos();
		return temp.reduce();
	}

	/**********/

	Expression Expression::tan(){
		return Expression(TAN, tree);
	}

	Expression Expression::ln(){
		return Expression(LN, tree);
	}

	Expression Expression::sin(){
		return Expression(SIN, tree);
	}

	Expression Expression::cos(){
		return Expression(COS, tree);
	}

	Expression::Expression(FunctionType fn, Multitree * arg){
		tree = new Multitree;
		tree->symbol.type = FUNCTION;
		tree->symbol.func = fn;
		tree->childs = new ListOfChilds;
		tree->childs->inverted = false;
		tree->childs->next = NULL;
		tree->childs->subtree = copy_tree(arg);
	}

	Expression Expression::reduce(){
		//TODO: Put it to while (while reduced is not same as not reduced)
		Expression expr;
		/* Moved to canonicalize_tree
		Multitree * one = copy_tree(tree);
		Multitree * two = reduce_tree(one);
		Multitree * tmp;
		rehang_tree(two);
		sort_tree(two);
		//Reduce tree, until nothing more can be done 
		//(when calling rehang, some nodes can come up that could be reduced more)
		while (treecmp(one, two) != 0){
			delete_tree(one);
			one = reduce_tree(two);
			rehang_tree(one);
			sort_tree(one);
			tmp = two;
			two = one;
			one = tmp;
			//output_tree(one, std::cout);
//			std::cout << std::endl;
			//output_tree(two, std::cout);
//			std::cout << std::endl << std::endl;
		}
		*/

		expr.tree = canonicalize_tree(tree);
		return expr;
	}

	/*Expression operator+(Number & number, Expression & ex){
		return ex+number; //It is same and will be sorted;
	}

	Expression operator-(Number & number, Expression & ex){
		return Expression(number)-ex; //It is same and will be sorted;
	}

	Expression operator*(Number & number, Expression & ex){
		return ex*number;
	}

	Expression operator/(Number & number, Expression & ex){
		return Expression(number)/ex;
	}*/

	Expression::Expression(int i){
		tree = new Multitree;
		tree->symbol.type=NUMBER;
		tree->symbol.number=i;
		tree->childs = NULL;
	}

	Expression::Expression(double d){
		tree = new Multitree;
		tree->symbol.type=NUMBER;
		tree->symbol.number=d;
		tree->childs = NULL;
	}

	Expression Expression::diff(char * variable){
		Expression e2;
		e2.tree = diff_tree(tree, variable);
//		output_tree(e2.tree, std::cout);
		Expression e3 = e2.reduce();
		return e3;
	}

	Expression Expression::diff(SymCe::Expression &variable){
		if(variable.tree->symbol.type != VARIABLE){
			throw OnlyVariable();
		}else{
			return diff(variable.tree->symbol.name);
		}
	}

	
	Expression Expression::replace_variable(char * variable, Expression & ex){
		if(!good_variable_name(variable)){
			throw BadVariable();
		}
		Expression expr;
		expr.tree = replace_variable_tree(tree, variable, ex.tree);
		Expression ex2 = expr.reduce();
		return ex2;
	}

	Expression Expression::replace_variable(Expression & variable, Expression & ex){
		if(variable.tree->symbol.type != VARIABLE){
			throw OnlyVariable();
		}else{
			return replace_variable(variable.tree->symbol.name, ex);
		}
	}

	Expression Expression::expand(){
		Expression expr;
		Multitree * b = expand_tree(tree);
		expr.tree = b;
		sort_tree(expr.tree);
		return expr.reduce();
	//	return expr;
	}

	Expression Expression::taylor(Number center, unsigned short int terms, char * variable){
		if(!good_variable_name(variable)){
			throw BadVariable();
		}
		Expression expr;
		expr.tree = taylorize(tree, center, terms, variable);
		return expr.reduce();
	}

	Expression Expression::taylor(Number center, unsigned short int terms, Expression & variable){
		if(variable.tree->symbol.type != VARIABLE){
			throw OnlyVariable();
		}else{
			return taylor(center, terms, variable.tree->symbol.name);
		}
	}

}











